package gugga.eventHelpers
{
	import flash.events.Event;
	
	/**
	 * <code>Listener</code> provide us with a mechanism of binding an event 
	 * to a consumer function. Optionally we could pass additional data to that 
	 * function if the <code>Listener</code> is created as merging. This gives us 
	 * the power to pass data, that we've decided not to keep in the event object. 
	 * <p>
	 * In Actionscript 2 GuggaFF this additional data is actually merged into the 
	 * event object, but that approach is not working in Actionscript 3. In Actionscript 3
	 * dynamic addition of new properties is possible only for objects marked as 
	 * <i>dynamic</i> and that's the reason to pass this data as an additional argument to 
	 * the consumer function.
	 * <p>
	 * The correct use of the <code>Listener</code> is through its static methods:
	 * <ul>
	 * 	<li>create()</li>
	 * 	<li>createMergingListener()</li>
	 * 	<li>createSingleTimeListener()</li>
	 * 	<li>createSingleTimeMergingListener()</li>
	 * </ul>
	 */
	public class Listener
	{
		private var mDataObject : *;
		private var mConsumerFunction : Function;
		private var mListenOnce : Boolean;
		private var mHandleEventDelegate : Function;
		private var mTargetEventDescriptor : EventDescriptor;
		private var mListening : Boolean;
		private var	mIsMerging : Boolean
		private var mUseWeakReference : Boolean;
	
		public function get Listening() : Boolean
		{
			return mListening;
		}
		
		public function get TargetEventDescriptor() : EventDescriptor
		{
			return mTargetEventDescriptor;
		}
		 
		public function Listener(
			aTargetEventDescriptor : EventDescriptor, 
			aConsumerFunction : Function, 
			aForwardOnce : Boolean = false,
			aDataObject : * = undefined,
			aIsMerging : Boolean = false,
			aUseWeakReference : Boolean = false) 
		{
			mTargetEventDescriptor = aTargetEventDescriptor;
			mConsumerFunction = aConsumerFunction;
			mDataObject = aDataObject;
			mListenOnce = aForwardOnce;
			mIsMerging = aIsMerging
			mUseWeakReference = aUseWeakReference;
			
			mListening = false;
		}
		 
		public function start() : void
		{
			mListening = true;
			mTargetEventDescriptor.EventSource.addEventListener(
				mTargetEventDescriptor.EventName, 
				handleEvent, false, 0.0, mUseWeakReference);
		}
		
		public function stop() : void
		{
			mListening = false;
			mTargetEventDescriptor.EventSource.removeEventListener(
				mTargetEventDescriptor.EventName, 
				handleEvent);
		}
		
		private function handleEvent(ev : Event) : void
		{
			if (mListenOnce)
			{
				this.stop();
			}
			
			if (mIsMerging)
			(
				mConsumerFunction(ev, mDataObject)
			)
			else
			{
				mConsumerFunction(ev)
			}
		}
		
		public static function create(
			aTargetEventDescriptor : EventDescriptor, 
			aConsumerFunction : Function, 
			aDataObject : Object, 
			aForwardOnce : Boolean,
			aUseWeakReference : Boolean = false) : Listener
		{		
			var result : Listener = new Listener(
				aTargetEventDescriptor, 
				aConsumerFunction, 
 				aForwardOnce,
				aDataObject,
				aUseWeakReference);
									
			result.start();
			
			return result;
		}	
		
		public static function createDataForwardingListener(
			aTargetEventDescriptor : EventDescriptor, 
			aConsumerFunction : Function, 
			aDataObject : Object,
			aUseWeakReference : Boolean = false) : Listener
		{		
			var result : Listener = new Listener(
				aTargetEventDescriptor, 
				aConsumerFunction, 
 				false,
				aDataObject,
				true,
				aUseWeakReference);
									
			result.start();
			
			return result;
		}	
		
		public static function createSingleTimeListener(
			aTargetEventDescriptor : EventDescriptor, 
			aConsumerDelegate : Function, 
			aUseWeakReference : Boolean = false) : Listener
		{		
			var result : Listener = new Listener(
				aTargetEventDescriptor, 
				aConsumerDelegate,  
				true,
				null,
				false,
				aUseWeakReference);		
							
			result.start();
			
			return result;
		}	
	
		public static function createSingleTimeDataForwardingListener(
			aTargetEventDescriptor : EventDescriptor, 
			aConsumerFunction : Function, 
			aDataObject : Object, 
			aUseWeakReference : Boolean = false) : Listener
		{		
			var result : Listener = new Listener(
				aTargetEventDescriptor, 
				aConsumerFunction, 
				true,
				aDataObject, 
				true,
				aUseWeakReference);
									
			result.start();
			
			return result;
		}
	}
}
